package com.franklin.ideaplugin.easytesting.core.registry;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.StrUtil;
import com.franklin.ideaplugin.easytesting.common.entity.ETRsp;
import com.franklin.ideaplugin.easytesting.common.log.ILogger;
import com.franklin.ideaplugin.easytesting.common.log.LoggerFactory;
import com.franklin.ideaplugin.easytesting.common.utils.JsonUtils;
import com.franklin.ideaplugin.easytesting.common.utils.MyPathUtil;
import com.franklin.ideaplugin.easytesting.core.rpc.NettyServer;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.franklin.ideaplugin.easytesting.common.utils.MyPathUtil.getCacheBasePath;

/**
 * @author Ye Junhui
 * @since 2023/5/12
 */
public class FileRegistry {

    private static final ILogger log = LoggerFactory.getLogger(FileRegistry.class);

    private final static String JRE_LIB = "jre/lib";

    /**
     * idea maven 工程编译类目录
     */
    private final static String IDEA_CLASSES_SYMBOL = "/target/classes";
    private final static Set<String> registryPaths = new HashSet<>();
    private final static String IDEA_MAVEN_SYMBOL = "/src/main/java";

    /**
     * 通知执行结果
     * @param executePath
     * @param etRsp
     */
    public static void registryResult(String executePath, ETRsp<Object> etRsp){
        String resultPath = executePath + "/result";
        resultPath = resultPath.replace('\\','/');
        FileUtil.writeString(JsonUtils.toJSONString(etRsp),resultPath,StandardCharsets.UTF_8);
    }

    /**
     * 获取方法路径
     * @param clazz
     * @param method
     * @return
     */
    private static String getMethodKey(Class<?> clazz,Method method){
        String classQualifiedName = clazz.getName();
        String classFilePath = classQualifiedName.replaceAll("\\.", "/");
        String classFileName = classFilePath + ".class";
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();

        URL resource = contextClassLoader.getResource(classFileName);
        if (Objects.isNull(resource)) {
            return null;
        }
        String path = resource.getPath().replace("file:/","");
        path = URLDecoder.decodeForPath(path, StandardCharsets.UTF_8);

        if (path.contains(IDEA_CLASSES_SYMBOL)) {
            int index = path.indexOf(IDEA_CLASSES_SYMBOL);
            path = path.substring(MyPathUtil.getIdeaPrefixIndex(), index);
        }

        String className = clazz.getSimpleName();
        String methodName = method.getName();
        String basePath = System.getProperty("user.dir").replace('\\','/');
        path = path.replace(basePath,"");

        path = path + IDEA_MAVEN_SYMBOL + "/" + classFilePath;

        String paramType = Arrays.stream(method.getParameterTypes())
                .map(Class::getName)
                .collect(Collectors.joining(","));
        paramType = "(" + paramType + ")";
        String key = Stream.of(path,methodName, paramType)
                .collect(Collectors.joining("/"));
        key = key.replace('.','_');
        key = MyPathUtil.deleteErrorChars(key);
        key = key.replace('\\','/');
        return key;
    }

    public static void registryServerForLib(String appName, String libPath, int port) {
        String libName = getPathServiceName(libPath);
        String registryServicePath = getRegistryServicePath(appName, libName);
        log.info("Easy-Testing -> registry service package {}", registryServicePath);
        FileUtil.writeString(String.valueOf(port), registryServicePath, StandardCharsets.UTF_8);
        registryPaths.add(registryServicePath);
    }

    public static String getPathServiceName(String path) {
        return path
                .replace('.','_')
                .replace("/", "_")
                .replace("\\", "_")
                .replace(":", "_");
    }

    /**
     * 服务注册
     * @param appName
     * @param port
     */
    public static void registryServer(String appName, int port) {
        JdkFileRegistry.registryJdk(appName,port);
        String path = System.getProperty("java.class.path");
        if (StrUtil.isBlank(path)) {
            return;
        }
        Map<Boolean, List<String>> isIdeaClassMap = Arrays.stream(path.split(MyPathUtil.getLibSeparator()))
                .map(lib -> lib.replace('\\','/'))
                .collect(Collectors.groupingBy(lib -> lib.contains(IDEA_CLASSES_SYMBOL)));
        List<String> ideaLibList = isIdeaClassMap.getOrDefault(true, Collections.emptyList());
        List<String> otherLibList = isIdeaClassMap.getOrDefault(false, Collections.emptyList());

        ideaLibList.forEach(lib -> registryServerForIdeaPath(lib, appName, port));
        otherLibList.forEach(lib -> {
            try {
                if (lib.contains(JRE_LIB)) {
                    int index = lib.indexOf(JRE_LIB);
                    lib = lib.substring(0, index + JRE_LIB.length());
                }
                FileRegistry.registryServerForLib(appName, lib, port);
            } catch (Exception e) {
//                            log.error("Easy-Testing -> method registry fail , {}" ,registryPath);
            }
        });
    }

    /**
     * idea
     *
     * @param path
     * @param appName
     * @param port
     */
    private static void registryServerForIdeaPath(String path, String appName, int port) {
        if (!path.contains(IDEA_CLASSES_SYMBOL)) {
            return;
        }
        int index = path.indexOf(IDEA_CLASSES_SYMBOL);
        path = path.substring(0, index);
        String serviceName = getPathServiceName(path);
        String registryServicePath = getRegistryServicePath(appName, serviceName);
        if (registryPaths.contains(registryServicePath)) {
            return;
        }
        log.info("Easy-Testing -> registry service package {}", registryServicePath);
        FileUtil.writeString(String.valueOf(port), registryServicePath, StandardCharsets.UTF_8);
        registryPaths.add(registryServicePath);
    }


    /**
     * 注册服务路径
     *
     * @param appName
     * @return
     */
    public static String getRegistryServicePath(String appName, String serviceName) {
        String registryBasePath = getRegistryBasePath();
        //服务目录
        return registryBasePath + "/" + serviceName + "/etServer_" + appName;
    }

    /**
     * 获取注册中心根目录
     *
     * @return
     */
    public static String getRegistryBasePath() {
        return getCacheBasePath("serviceList");
    }

    /**
     * 参数缓存路径
     * @param key
     * @return
     */
    private static String getParamCachePath(String key){
        if (key.startsWith("/")){
            return getCacheBasePath("cache") + "/method" + key;
        }
        return getCacheBasePath("cache") + "/method/" + key;
    }

    /**
     * 执行结果缓存路径
     * @param key
     * @param executeTime
     * @return
     */
    private static String getExecuteResultPath(String key,Long executeTime){
        return getParamCachePath(key) + "/" + executeTime;
    }

    /**
     * 服务下线
     * @param appName
     */
    public static void shutDown(String appName) {
        registryPaths.stream()
                .map(FileUtil::file)
                .filter(File::isDirectory)
                .forEach(FileUtil::del);
        registryPaths.clear();
    }
}
